#pragma once
#include "Bind.h"
#include "MessageFilter.h"
#if (COMM_FEATURE_LIBEVENT==1)

#define RPC_FUNC_REGISTER(CLASS,NAME,R,...)	\
	BindMap::Instance()->set(#CLASS"::"#NAME, static_cast<IBind*>(new Bind<CLASS,R,## __VA_ARGS__>(this,&CLASS::NAME,#CLASS"::"#NAME)));

namespace COMM
{
	class COMM_API BindMap : public Singleton<BindMap>
	{
		MYLIB_NONCOPIED_CLASS(BindMap);
	public:
		BindMap();
		~BindMap();
		IBind* get(const char* classname);
		void set(const char* classname,IBind* bind);
		void clear();
	private:
		ThreadLock m_lock;
		void* m_map;
	};
	
	enum RPCError {
		RPC_SUCCESS = 0,
		RPC_SYSTEM_ERROR = 0x01000002, /*RPC method was not register.*/
		RPC_CONNECT_FAILURE,
		RPC_SEND_FAILURE,
		RPC_WAIT_TIMEOUT
	};

	class COMM_API RPCFilter : public MessageFilter
	{
	public:
		enum { TIMEOUT=10000 };
		RPCFilter();
		bool Call(MessageHandler* hanlder, const char* classname, const Arguments& args=Arguments(), 
			CommType* response=NULL, unsigned int timeoutMs=TIMEOUT);
	private:
		~RPCFilter();
		virtual bool OnMessage(MessageHandler* hanlder, const char* buffer, int size);
		virtual void OnClose(MessageHandler* hanlder, SocketClient::ConnectionState reason);
		void* m_inst_opaque;
	};

	class COMM_API RPC : public MessageReactor
	{
	public:
		RPC(const SocketAddress& address, bool asClient=false,
			int dispatchThreadCount=ThreadPool::DefaultThreadsCount, int dispatchIntervalMs=10,
			const char* crtfile=NULL, const char* keyfile=NULL);
		// used by client.
		bool Call(const char* classname, const Arguments& args=Arguments(), 
			CommType* response=NULL, unsigned int timeoutMs=RPCFilter::TIMEOUT,
			const char* address=NULL);
		List<MessageFilter*>& FilterList();
		// get the current MessageHandler which received RPC call, only invoked by RPC method inner.
		static MessageHandler* CurrentMessager();
		// get the current RPC::Call() error.
		static RPCError CurrentError();
	};



}

#endif



